"""
人员资源数据模型

定义人员资源的基本信息和能力。
"""

from dataclasses import dataclass, field
from datetime import date
from typing import Optional, List, Set
from enum import Enum


class ResourceRole(Enum):
    """资源角色枚举"""
    PROJECT_MANAGER = "PM"
    SYSTEM_ENGINEER = "SE"
    PROGRAMMER = "PG"
    TESTER = "TEST"
    DESIGNER = "DESIGN"
    ANALYST = "BA"
    ARCHITECT = "ARCH"
    CONSULTANT = "CONS"


class SkillLevel(Enum):
    """技能等级枚举"""
    BEGINNER = 1      # 初级
    JUNIOR = 2        # 初中级
    INTERMEDIATE = 3  # 中级
    SENIOR = 4        # 高级
    EXPERT = 5        # 专家级


@dataclass
class Resource:
    """
    人员资源信息模型

    Attributes:
        resource_id: 人员唯一标识符
        name: 姓名
        role: 主要角色
        skill_level: 技能等级（1-5）
        hourly_rate: 时薪（可选）
        max_hours_per_week: 每周最大工作时间
        available_from: 可用开始日期
        available_to: 可用结束日期
        skills: 技能标签集合
        department: 所属部门（可选）
        location: 工作地点（可选）
        is_contractor: 是否为外包人员
        cost_center: 成本中心（可选）
    """
    resource_id: str
    name: str
    role: ResourceRole
    skill_level: SkillLevel
    max_hours_per_week: int
    available_from: date
    available_to: date
    hourly_rate: Optional[float] = None
    skills: Set[str] = field(default_factory=set)
    department: Optional[str] = None
    location: Optional[str] = None
    is_contractor: bool = False
    cost_center: Optional[str] = None

    def __post_init__(self):
        """数据验证"""
        if self.available_from >= self.available_to:
            raise ValueError("资源可用开始日期必须早于结束日期")

        if not self.resource_id.strip():
            raise ValueError("资源ID不能为空")

        if not self.name.strip():
            raise ValueError("资源姓名不能为空")

        if self.max_hours_per_week <= 0:
            raise ValueError("每周最大工作时间必须大于0")

        if self.max_hours_per_week > 168:  # 一周最多168小时
            raise ValueError("每周最大工作时间不能超过168小时")

        if self.hourly_rate is not None and self.hourly_rate < 0:
            raise ValueError("时薪不能为负数")

    @property
    def availability_days(self) -> int:
        """计算可用天数"""
        return (self.available_to - self.available_from).days + 1

    @property
    def max_hours_per_day(self) -> float:
        """计算每日最大工作时间（假设5个工作日）"""
        return self.max_hours_per_week / 5.0

    def is_available_on_date(self, check_date: date) -> bool:
        """检查指定日期是否可用"""
        return self.available_from <= check_date <= self.available_to

    def has_skill(self, skill: str) -> bool:
        """检查是否具备指定技能"""
        return skill.lower() in {s.lower() for s in self.skills}

    def has_role(self, role: ResourceRole) -> bool:
        """检查是否匹配指定角色"""
        return self.role == role

    def meets_skill_requirement(self, required_level: SkillLevel) -> bool:
        """检查是否满足技能等级要求"""
        return self.skill_level.value >= required_level.value

    def can_work_on_task(self, required_role: ResourceRole,
                        required_skill_level: SkillLevel,
                        required_skills: Optional[Set[str]] = None) -> bool:
        """检查是否能够承担指定任务"""
        # 角色匹配检查
        if not self.has_role(required_role):
            return False

        # 技能等级检查
        if not self.meets_skill_requirement(required_skill_level):
            return False

        # 特定技能检查
        if required_skills:
            for skill in required_skills:
                if not self.has_skill(skill):
                    return False

        return True

    def calculate_cost(self, hours: float) -> Optional[float]:
        """计算指定工时的成本"""
        if self.hourly_rate is None:
            return None
        return self.hourly_rate * hours

    def to_dict(self) -> dict:
        """转换为字典格式"""
        return {
            'resource_id': self.resource_id,
            'name': self.name,
            'role': self.role.value,
            'skill_level': self.skill_level.value,
            'hourly_rate': self.hourly_rate,
            'max_hours_per_week': self.max_hours_per_week,
            'max_hours_per_day': round(self.max_hours_per_day, 2),
            'available_from': self.available_from.isoformat(),
            'available_to': self.available_to.isoformat(),
            'availability_days': self.availability_days,
            'skills': list(self.skills),
            'department': self.department,
            'location': self.location,
            'is_contractor': self.is_contractor,
            'cost_center': self.cost_center
        }

    @classmethod
    def from_dict(cls, data: dict) -> 'Resource':
        """从字典创建资源实例"""
        # 处理日期字段
        if isinstance(data['available_from'], str):
            data['available_from'] = date.fromisoformat(data['available_from'])
        if isinstance(data['available_to'], str):
            data['available_to'] = date.fromisoformat(data['available_to'])

        # 处理枚举字段
        if 'role' in data and isinstance(data['role'], str):
            data['role'] = ResourceRole(data['role'])
        if 'skill_level' in data and isinstance(data['skill_level'], int):
            data['skill_level'] = SkillLevel(data['skill_level'])

        # 处理技能集合
        if 'skills' in data and isinstance(data['skills'], list):
            data['skills'] = set(data['skills'])

        # 移除计算字段
        computed_fields = ['availability_days', 'max_hours_per_day']
        for field in computed_fields:
            data.pop(field, None)

        return cls(**data)